/**
 * HttpClient.java<br>
 *
 * @author aaronwong.sd@foxmail.com
 * @version 下午2:34:39
 */
package com.iwechat.httpclient;

import java.io.IOException;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.iwechat.util.PropertyUtils;

/**
 * http客户端工具
 *
 * @author aaronwong.sd@foxmail.com
 */
public class HttpClient {
    /** logger */
    private static final Logger                logger                      = LogManager.getLogger();
    private static final HttpClient            instance                    = new HttpClient();
    private HttpRequestRetryHandler            httpRequestRetryHandler     = new HttpRequestRetryHandlerImpl();
    private ConnectionKeepAliveStrategy        connectionKeepAliveStrategy = new ConnectionKeepAliveStrategyImpl();
    private PoolingHttpClientConnectionManager cm                          = null;
    private PropertyUtils                      config                      = PropertyUtils.getInstance();

    /**
     * @return the instance
     */
    public static HttpClient getInstance() {
        return instance;
    }

    private HttpClient() {
        // HTTP
        ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
        // HTTPS
        LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory> create().register("http", plainsf)
                .register("https", sslsf).build();
        cm = new PoolingHttpClientConnectionManager(registry);
        // 最大连接数
        int maxTotal = config.getIntValue("httpclient", "http.client.maxTotal");
        cm.setMaxTotal(maxTotal);
        // 每个路由基础的连接
        int maxPerRoute = config.getIntValue("httpclient", "http.client.maxPerRoute");
        cm.setDefaultMaxPerRoute(maxPerRoute);
        // 超时链接管理
        IdleConnectionMonitorThread idleM = new IdleConnectionMonitorThread(cm);
        idleM.start();
        logger.info("### init succeed! Pool maxTotal " + maxTotal + ", defaultMaxPerRoute " + maxPerRoute + ".");
    }

    public CloseableHttpResponse execute(HttpRequestBase request) throws ClientProtocolException, IOException {
        CloseableHttpResponse response = null;
        config(request);
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).setRetryHandler(httpRequestRetryHandler)
                .setKeepAliveStrategy(connectionKeepAliveStrategy).build();
        response = httpClient.execute(request, HttpClientContext.create());
        return response;
    }

    /**
     * 配置http请求
     *
     * @param httpRequestBase
     */
    private void config(HttpRequestBase httpRequestBase) {
        // httpRequestBase.setHeader("User-Agent", "Mozilla/5.0");
        // httpRequestBase.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        // httpRequestBase.setHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
        // httpRequestBase.setHeader("Accept-Charset", "ISO-8859-1,utf-8,gbk,gb2312;q=0.7,*;q=0.7");

        // 配置请求的超时设置
        int connectionRequestTimeout = config.getIntValue("httpclient", "http.client.connectionRequestTimeout");
        int connectTimeout = config.getIntValue("httpclient", "http.client.connectTimeout");
        int socketTimeout = config.getIntValue("httpclient", "http.client.socketTimeout");
        Builder builder = RequestConfig.custom();
        builder.setConnectionRequestTimeout(connectionRequestTimeout * 1000);
        builder.setConnectTimeout(connectTimeout * 1000);
        builder.setSocketTimeout(socketTimeout * 1000);
        httpRequestBase.setConfig(builder.build());
    }
}
